<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/1/2
 * Time: 15:35
 */

namespace common\business\org;


use common\business\DbHandler;
use common\business\EhrHelper;
use common\consts\CommonResources;
use common\consts\Consts;
use common\helpers\StringUtil;
use common\models\kingdee\OrgAdmin;
use common\models\OrgTree;
use common\result\ActionResult;

class OrgTreeService extends DbHandler
{
    /**
     * @var string
     */
    protected $_department_number;
    public function setDepartmentNumber($department_number){
        $this->_department_number = $department_number;
    }

    /**
     * @var integer
     */
    protected $_idx;

    /**
     * @var integer
     */
    protected $_lvl;

    /**
     * @var OrgAdmin
     */
    protected $_topOrg;

    /**
     * @var OrgTree
     */
    protected $_topOrgTreeNode;
//    /**
//     * @var int
//     */
//    protected $_totalCount;
    /**
     * @param callback|null $writeBackHandler
     * @return ActionResult
     */
    public function sync($writeBackHandler = null) {
//        $this->_idx = 1;
//        $this->_totalCount = OrgAdmin::find()->count();
        $apiHandler = new OrgTreeApiHandler();

        $totalResult = new ActionResult();
        $isSyncTopSuccess = $this->syncTopOrgAndTopDepartment($totalResult, $writeBackHandler);
        if (!$isSyncTopSuccess){
            return new ActionResult(false, CommonResources::ACTION_FAIL_MSG('Sync', 'Department', $this->getErrorsMessage()));
        }

        $this->syncChildrenWithParentDepartment($this->_topOrg, $this->_topOrgTreeNode, $totalResult, $writeBackHandler);
        $this->_topOrgTreeNode->rgt = ++$this->_idx;
        $updateResult = $apiHandler->updateOrgTree($this->_topOrgTreeNode);
        if (!$updateResult->isSuccess){
            $totalResult->addSubResult($updateResult);
            $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
        }
//        $this->saveRecordUnsafe($this->_topOrgTreeNode);

        return $totalResult;
    }

    /**
     * 需要找到最顶层Org，并且寻找企业微信是是否有这个节点，如果名字不一样要更新
     * @param $totalResult ActionResult
     * @param callback|null $writeBackHandler
     * @return bool
     */
    protected function syncTopOrgAndTopDepartment($totalResult, $writeBackHandler = null){
        $topIsRoot = false;
        $apiHandler = new OrgTreeApiHandler();

        $isSkipped = false;

        if(!StringUtil::isNullOrWhiteSpace($this->_department_number)){
            $topOrg = OrgAdmin::findOne([
                'FNUMBER' => $this->_department_number,
            ]);
            $topIsRoot = false;

            if ($topOrg->FPARENTID == null){
                $this->_idx = 0;
                $this->_lvl = 0;
            }
            else {
                $topParentOrg = OrgAdmin::findOne([
                    'FID' => $topOrg->FPARENTID,
                ]);
                $topParentTreeNode = OrgTree::findOne(['number' => $topParentOrg->FNUMBER]);
                $this->_idx = $topParentTreeNode->lft;
                $this->_lvl = $topParentTreeNode->lvl;
            }
        }
//        否则拿顶层节点
        else{
            $topOrg = OrgAdmin::findOne([
                'FPARENTID' => null,
            ]);
            $topIsRoot = true;
            $this->_idx = 0;
        }

        if (!$topOrg)
        {
            $this->addError('Find Top Org', 'Top Org Not Found');
            $totalResult->addSubResult(new ActionResult(false, $this->getErrorsMessage()));
            $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
            return false;
        }

        if ($topIsRoot){
            $topOrgTreeNode = OrgTree::findOne([
                'name' => EhrHelper::getName4QywxDepartment($topOrg),
                'number' => $topOrg->FNUMBER,
                'parent_id' => Consts::ID_UNKNOWN,
            ]);
        }
        else {
            OrgTree::deleteAll(
                'number=:number and name<>:name',
                [
                    ':number' => $topOrg->FNUMBER,
                    ':name' => EhrHelper::getName4QywxDepartment($topOrg),
                ]
            );

            $topOrgTreeNode = OrgTree::findOne([
                'name' => EhrHelper::getName4QywxDepartment($topOrg),
                'number' => $topOrg->FNUMBER,
            ]);
        }

        if (!$topOrgTreeNode){
            $topOrgTreeNode = new OrgTree([
                'name' =>  EhrHelper::getName4QywxDepartment($topOrg),
                'display_name' => $topOrg->FDISPLAYNAME_L2,
                'kd_id' => $topOrg->FID,
                'number' => $topOrg->FNUMBER,
                'hr_status' => Consts::SYNC_STATUS_FINISHED,
                'active' => Consts::YES,
                'visible' => Consts::YES,
                'collapsed' => Consts::YES,
                'movable_u' => Consts::YES,
                'movable_d' => Consts::YES,
                'movable_l' => Consts::YES,
                'movable_r' => Consts::YES,
                'removable' => Consts::YES,
                'lvl' => ++$this->_lvl,
                'lft' => ++$this->_idx,
            ]);

            $createResult = $apiHandler->createOrgTree($topOrgTreeNode);
            if (!$createResult->isSuccess){
                $totalResult->addSubResult($createResult);
                $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
                return false;
            }

            $topOrgTreeNode = OrgTree::findOne([
                'number' => $topOrg->FNUMBER
            ]);
        }

        if ($topOrgTreeNode->hr_status == Consts::SYNC_STATUS_SYNCHRONIZING) {
            $this->addError('Sync Top', 'Other Thread is Syncing this record now.');
            $totalResult->addSubResult(new ActionResult(false, $this->getErrorsMessage(), true));
            $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
            return false;
        }

        //状态变成更新中
        $topOrgTreeNode->hr_status = Consts::SYNC_STATUS_SYNCHRONIZING;
//        $topOrgTreeNode->parent_id = Consts::ID_UNKNOWN;
//        $topOrgTreeNode->qywx_id = Consts::ID_UNKNOWN;
//        $topOrgTreeNode->parent_qywx_id = Consts::ID_UNKNOWN;
//        $topOrgTreeNode->qywx_order = 0;
//        $topOrgTreeNode->mdm_id = Consts::ID_UNKNOWN;
        $topOrgTreeNode->kd_id = $topOrg->FID;
        $topOrgTreeNode->display_name = $topOrg->FDISPLAYNAME_L2;
        $topOrgTreeNode->number = $topOrg->FNUMBER;

        $topOrgTreeNode->lvl = ++$this->_lvl;
        $topOrgTreeNode->lft = ++$this->_idx;
        //状态变成更新完成
        $topOrgTreeNode->hr_status = Consts::SYNC_STATUS_FINISHED;
        $updateResult = $apiHandler->updateOrgTree($topOrgTreeNode);
        if (!$updateResult->isSuccess){
            $totalResult->addSubResult($updateResult);
            $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
            return false;
        }
        if ($updateResult->isSkipped)
            $isSkipped = true;

        $this->_topOrg =  $topOrg;
        $this->_topOrgTreeNode = $topOrgTreeNode;
        $totalResult->addSubResult(new ActionResult(true, CommonResources::ACTION_SUCCESS_MSG('Sync Top', 'Org Tree Node'), $isSkipped));
        $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
        return true;
    }

    /**
     * @param $org OrgAdmin
     * @param $parentOrgTreeNode OrgTree
     * @param $totalResult ActionResult
     * @param callback|null $writeBackHandler
     * @return OrgTree
     */
    protected function syncSingleOrgWithParent($org, $parentOrgTreeNode, $totalResult, $writeBackHandler = null){
        $isSkipped = false;
        $apiHandler = new OrgTreeApiHandler();

        $orgTreeNodeInDb = OrgTree::findOne([
            'name' => EhrHelper::getName4QywxDepartment($org),
            'parent_number' => $parentOrgTreeNode->number,
        ]);

        if (!$orgTreeNodeInDb){
            $newOrgTreeNode = new OrgTree([
                'name' =>  EhrHelper::getName4QywxDepartment($org),
                'display_name' => $org->FDISPLAYNAME_L2,
                'parent_id' => $parentOrgTreeNode->id,
                'parent_number' => $parentOrgTreeNode->number,
                'kd_id' => $org->FID,
                'number' => $org->FNUMBER,
                'parent_kd_id' => $parentOrgTreeNode->kd_id,
                'parent_qywx_id' => $parentOrgTreeNode->qywx_id,
                'hr_status' => Consts::SYNC_STATUS_FINISHED,
                'active' => Consts::YES,
                'visible' => Consts::YES,
                'collapsed' => Consts::YES,
                'movable_u' => Consts::YES,
                'movable_d' => Consts::YES,
                'movable_l' => Consts::YES,
                'movable_r' => Consts::YES,
                'removable' => Consts::YES,
            ]);
            $newOrgTreeNode->lvl = $parentOrgTreeNode->lvl + 1;
            $newOrgTreeNode->lft = ++$this->_idx;

            $createResult = $apiHandler->createOrgTree($newOrgTreeNode);
            if (!$createResult->isSuccess){
                $totalResult->addSubResult($createResult);
                $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
                return null;
            }

            $orgTreeNodeInDb = OrgTree::findOne([
                'number' => $org->FNUMBER
            ]);
        }

        if ($orgTreeNodeInDb->hr_status == Consts::SYNC_STATUS_SYNCHRONIZING) {
            $this->addError('Sync Top', 'Other Thread is Syncing this record now.');
            $totalResult->addSubResult(new ActionResult(false, $this->getErrorsMessage(), true));
            $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
            return null;
        }
        //状态变成更新中
        $orgTreeNodeInDb->hr_status = Consts::SYNC_STATUS_SYNCHRONIZING;
        $orgTreeNodeInDb->parent_number = $parentOrgTreeNode->number;
        $orgTreeNodeInDb->parent_id = $parentOrgTreeNode->id;

        $orgTreeNodeInDb->kd_id = $org->FID;
        $orgTreeNodeInDb->parent_kd_id = $org->FPARENTID;
        $orgTreeNodeInDb->number = $org->FNUMBER;
        $orgTreeNodeInDb->display_name = $org->FDISPLAYNAME_L2;
        $orgTreeNodeInDb->lvl = $parentOrgTreeNode->lvl + 1;
        $orgTreeNodeInDb->lft = ++$this->_idx;
        //状态变成更新完成
        $orgTreeNodeInDb->hr_status = Consts::SYNC_STATUS_FINISHED;
        $updateResult = $apiHandler->updateOrgTree($orgTreeNodeInDb);
        if (!$updateResult->isSuccess){
            $totalResult->addSubResult($updateResult);
            $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
            return null;
        }
        if ($updateResult->isSkipped)
            $isSkipped = true;

        $totalResult->addSubResult(new ActionResult(true, CommonResources::ACTION_SUCCESS_MSG('Sync Single', 'Department'), $isSkipped));
        $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
        return $orgTreeNodeInDb;
    }

    /**
     * @param $parentOrg OrgAdmin
     * @param $parentOrgTreeNode OrgTree
     * @param $totalResult ActionResult
     * @param callback|null $writeBackHandler
     */
    protected function syncChildrenWithParentDepartment($parentOrg, $parentOrgTreeNode, $totalResult, $writeBackHandler = null){
        $apiHandler = new OrgTreeApiHandler();
        $childrenOrgs = OrgAdmin::findAll([
            'FPARENTID' => $parentOrg->FID,
        ]);
        if (sizeof($childrenOrgs) == 0){
            return;
        }
        foreach ($childrenOrgs as $childOrg){
            $childOrgTreeNode = $this->syncSingleOrgWithParent($childOrg, $parentOrgTreeNode, $totalResult, $writeBackHandler);
            if ($childOrgTreeNode){
                $this->syncChildrenWithParentDepartment($childOrg, $childOrgTreeNode, $totalResult, $writeBackHandler);

                $childOrgTreeNode->rgt = ++$this->_idx;
//                $this->saveRecordUnsafe($childOrgTreeNode);

                $updateResult = $apiHandler->updateOrgTree($childOrgTreeNode);
                if (!$updateResult->isSuccess){
                    $totalResult->addSubResult($updateResult);
                    $this->executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler);
                }
            }
        }
    }
}